//-----------------------------------------------------------------------------
// File: DeviceControl.cs
//
// Copyright (c) Dmitry Shuklin. All rights reserved.
//-----------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D = Microsoft.DirectX.Direct3D;
using Cerebrum.Direct3D.Forms.Internal;

namespace Cerebrum.Direct3D.Forms
{
	public class DeviceControl : Cerebrum.Direct3D.Forms.Control 
	{
		private System.ComponentModel.IContainer components = null;

		public DeviceControl()
		{
			m_RenderTarget = null;
			frameMoving = true;
			singleStep = false;
			startFullscreen = false;

			// This call is required by the Windows Form Designer.
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
		}
		#endregion

	
	
		private int appPausedCount = 0; // How many times has the app been paused (and when can it resume)?

	
		protected bool showCursorWhenFullscreen; // Whether to show cursor when fullscreen
		protected bool clipCursorWhenFullscreen; // Whether to limit cursor pos when fullscreen
		protected bool startFullscreen; // Whether to start up the app in fullscreen mode

	
		protected System.Drawing.Size storedSize;
		protected System.Drawing.Point storedLocation;

	
		// We need to keep track of our enumeration settings
		protected D3DEnumeration enumerationSettings;
		protected D3DSettings graphicsSettings;
		

		protected bool isMaximized = false; // Are we maximized?
		protected bool isHandlingSizeChanges = true; // Are we handling size changes?

		// Main objects used for creating and rendering the 3D scene
		protected PresentParameters presentParams; // Parameters for CreateDevice/Reset
		protected Microsoft.DirectX.Direct3D.Device m_Device; // The rendering m_Device
		public Microsoft.DirectX.Direct3D.Device Device
		{
			get
			{
				return m_Device;
			}
		}
		//protected RenderStates renderState;
		//protected SamplerStates sampleState;
		//protected TextureStates textureStates;
		private Caps graphicsCaps;           // Caps for the m_Device
		protected Caps Caps { get { return graphicsCaps; } }
		private CreateFlags behavior;     // Indicate sw or hw vertex processing
		protected BehaviorFlags BehaviorFlags { get { return new BehaviorFlags(behavior); } }

		// The window we will render too
		protected System.Windows.Forms.Control m_RenderTarget;
		public System.Windows.Forms.Control RenderTarget 
		{ 
			get 
			{ 
				return m_RenderTarget; 
			} 
			set 
			{
				if(m_RenderTarget != value)
				{
					ready = false;
					if(m_RenderTarget!=null)
					{
						m_RenderTarget.Resize -= new EventHandler(this.RenderTarget_Resize);
						m_RenderTarget.MouseDown -= new MouseEventHandler(this.RenderTarget_MouseDown);
						m_RenderTarget.Paint -= new PaintEventHandler(this.RenderTarget_Paint);
						m_RenderTarget.MouseUp -= new MouseEventHandler(this.RenderTarget_MouseUp);
						m_RenderTarget.MouseMove -= new MouseEventHandler(this.RenderTarget_MouseMove);
						m_RenderTarget.MouseWheel -= new MouseEventHandler(this.RenderTarget_MouseWheel);
						m_RenderTarget.MouseEnter -= new EventHandler(this.RenderTarget_MouseEnter);
						m_RenderTarget.MouseLeave -= new EventHandler(this.RenderTarget_MouseLeave);
						m_RenderTarget.Click -= new EventHandler(this.RenderTarget_Click);
						m_RenderTarget.DoubleClick -= new EventHandler(this.RenderTarget_DoubleClick);
						m_RenderTarget.HandleCreated -= new EventHandler(this.RenderTarget_HandleCreated);
						m_RenderTarget.HandleDestroyed -= new EventHandler(this.RenderTarget_HandleDestroyed);
						m_RenderTarget.VisibleChanged -= new EventHandler(this.RenderTarget_VisibleChanged);
						m_RenderTarget.GotFocus -= new EventHandler(this.RenderTarget_GotFocus);
						m_RenderTarget.Move -= new EventHandler(this.RenderTarget_Move);
						m_RenderTarget.Disposed -= new EventHandler(this.RenderTarget_Disposed);
					}
					m_RenderTarget = value;
					if(m_RenderTarget!=null)
					{
						this.SetBounds(0, 0, m_RenderTarget.ClientSize.Width, m_RenderTarget.ClientSize.Height, BoundsSpecified.All);

						m_RenderTarget.Resize += new EventHandler(this.RenderTarget_Resize);
						m_RenderTarget.MouseDown += new MouseEventHandler(this.RenderTarget_MouseDown);
						m_RenderTarget.Paint += new PaintEventHandler(this.RenderTarget_Paint);
						m_RenderTarget.MouseUp += new MouseEventHandler(this.RenderTarget_MouseUp);
						m_RenderTarget.MouseMove += new MouseEventHandler(this.RenderTarget_MouseMove);
						m_RenderTarget.MouseWheel += new MouseEventHandler(this.RenderTarget_MouseWheel);
						m_RenderTarget.MouseEnter += new EventHandler(this.RenderTarget_MouseEnter);
						m_RenderTarget.MouseLeave += new EventHandler(this.RenderTarget_MouseLeave);
						m_RenderTarget.Click += new EventHandler(this.RenderTarget_Click);
						m_RenderTarget.DoubleClick += new EventHandler(this.RenderTarget_DoubleClick);
						m_RenderTarget.HandleCreated += new EventHandler(this.RenderTarget_HandleCreated);
						m_RenderTarget.HandleDestroyed += new EventHandler(this.RenderTarget_HandleDestroyed);
						m_RenderTarget.VisibleChanged += new EventHandler(this.RenderTarget_VisibleChanged);
						m_RenderTarget.GotFocus += new EventHandler(this.RenderTarget_GotFocus);
						m_RenderTarget.Move += new EventHandler(this.RenderTarget_Move);
						m_RenderTarget.Disposed += new EventHandler(this.RenderTarget_Disposed);

						ready = true;

						this.RenderTarget_VisibleChanged(m_RenderTarget, System.EventArgs.Empty);
						
						storedSize = m_RenderTarget.ClientSize;
						storedLocation = m_RenderTarget.Location;
					}
				}
			} 
		}



		// Internal variables for the state of the app
		protected bool windowed;
		protected bool active;
		protected bool ready;
		protected bool hasFocus;
		protected bool isMultiThreaded = false;

		// Internal variables used for timing
		protected bool frameMoving;
		protected bool singleStep;

		//private bool isClosing = false; // Are we closing?
		protected bool isChangingFormStyle = false; // Are we changing the forms style?
		protected bool isWindowActive = true; // Are we waiting for got focus?

		protected string deviceStats;// String to hold D3D m_Device stats
		private bool deviceLost = false;


		// Overridable functions for the 3D scene created by the app
		protected virtual bool ConfirmDevice(Caps caps, VertexProcessingType vertexProcessingType, 
			Format adapterFormat, Format backBufferFormat) { return true; }
		protected virtual void OneTimeSceneInitialization() { /* Do Nothing */ }
		
		protected virtual void InitializeDeviceObjects(System.Object sender, System.EventArgs e) 
		{
			this.OnInitializeDeviceObjects(new DeviceEventArgs(this.m_Device));
		}
		
		protected virtual void RestoreDeviceObjects(System.Object sender, System.EventArgs e) 
		{
			this.OnRestoreDeviceObjects(new DeviceEventArgs(this.m_Device));
		}

		protected virtual void InvalidateDeviceObjects(System.Object sender, System.EventArgs e) 
		{
			this.OnInvalidateDeviceObjects(new DeviceEventArgs(this.m_Device));
		}
		protected virtual void DeleteDeviceObjects(System.Object sender, System.EventArgs e) 
		{
			this.OnDeleteDeviceObjects(new DeviceEventArgs(this.m_Device));
		}


		/// <summary>
		/// Displays sample exceptions to the user
		/// </summary>
		/// <param name="e">The exception that was thrown</param>
		/// <param name="Type">Extra information on how to handle the exception</param>
		public void HandleDeviceException(System.Exception e, ApplicationMessage type)
		{
			if(type!=ApplicationMessage.WarnSwitchToRef)
			{
				if(this.m_Connector!=null)
				{
					Cerebrum.Integrator.DomainContext domainContext = this.DomainContext;
					if(domainContext!=null)
					{
						if(domainContext.Application!=null)
						{
							Cerebrum.Integrator.Application app = domainContext.Application as Cerebrum.Integrator.Application;
							if(app!=null && e!=null)
								app.ProcessException(e, "3D.HandleDeviceException");
						}
					}
				}
			}
			// Build a message to display to the user
			string strMsg = string.Empty;
			if (e != null)
				strMsg = e.Message;

			if (ApplicationMessage.ApplicationMustExit == type)
			{
				strMsg  += "\n\nThis sample will now exit.";
				System.Windows.Forms.MessageBox.Show(strMsg, m_RenderTarget.Text, 
					System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);

				// Close the window, which shuts down the app
				if (m_RenderTarget.IsHandleCreated)
					m_RenderTarget.Dispose();
			}
			else
			{
				if (ApplicationMessage.WarnSwitchToRef == type)
					strMsg += "\n\nSwitching to the reference rasterizer,\n";
				strMsg += "a software m_Device that implements the entire\n";
				strMsg += "Direct3D feature set, but runs very slowly.";

				System.Windows.Forms.MessageBox.Show(strMsg, m_RenderTarget.Text, 
					System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
			}
		}

		/// <summary>
		/// Picks the best graphics device, and initializes it
		/// </summary>
		/// <returns>true if a good device was found, false otherwise</returns>
		public bool CreateGraphicsDevice()
		{
			presentParams = new PresentParameters();
			graphicsSettings = new D3DSettings();
			enumerationSettings = new D3DEnumeration();
			enumerationSettings.ConfirmDeviceCallback = new D3DEnumeration.ConfirmDeviceCallbackType(this.ConfirmDevice);
			enumerationSettings.Enumerate();

			if (m_RenderTarget.Cursor == null)
			{
				// Set up a default cursor
				m_RenderTarget.Cursor = System.Windows.Forms.Cursors.Default;
			}
			// if our render target is the main window and we haven't said 
			// ignore the menus, add our menu
			//if ((m_RenderTarget == this) && (isUsingMenus))
			//	this.Menu = mnuMain;

			try
			{
				ChooseInitialSettings();

				// Initialize the application timer
				//DXUtil.Timer(DirectXTimer.Start);
				// Initialize the app's custom scene stuff
				OneTimeSceneInitialization();
				// Initialize the 3D environment for the app
				InitializeEnvironment();
			}
				/*catch (SampleException d3de)
				{
					HandleDeviceException(d3de, ApplicationMessage.ApplicationMustExit);
					return false;
				}*/
			catch(System.Exception ex)
			{
				HandleDeviceException(ex, ApplicationMessage.ApplicationMustExit);
				return false;
			}

			// The app is ready to go
			ready = true;

			return true;
		}

		
		/// <summary>
		/// Choose the initial settings for the application
		/// </summary>
		/// <returns>true if the settings were initialized</returns>
		public bool ChooseInitialSettings()
		{
			bool foundFullscreenMode = FindBestFullscreenMode(false, false);
			bool foundWindowedMode = FindBestWindowedMode(false, false);
			if (startFullscreen && foundFullscreenMode)
				graphicsSettings.IsWindowed = false;

			if (!foundFullscreenMode && !foundWindowedMode)
				throw new NoCompatibleDevicesException();

			return (foundFullscreenMode || foundWindowedMode);
		}

		
		/// <summary>
		/// Sets up graphicsSettings with best available windowed mode, subject to 
		/// the doesRequireHardware and doesRequireReference constraints.  
		/// </summary>
		/// <param name="doesRequireHardware">Does the m_Device require hardware support</param>
		/// <param name="doesRequireReference">Does the m_Device require the ref m_Device</param>
		/// <returns>true if a mode is found, false otherwise</returns>
		public bool FindBestWindowedMode(bool doesRequireHardware, bool doesRequireReference)
		{
			// Get display mode of primary adapter (which is assumed to be where the window 
			// will appear)
			DisplayMode primaryDesktopDisplayMode = Manager.Adapters[0].CurrentDisplayMode;

			GraphicsAdapterInfo bestAdapterInfo = null;
			GraphicsDeviceInfo bestDeviceInfo = null;
			DeviceCombo bestDeviceCombo = null;

			foreach (GraphicsAdapterInfo adapterInfo in enumerationSettings.AdapterInfoList)
			{
				foreach (GraphicsDeviceInfo deviceInfo in adapterInfo.DeviceInfoList)
				{
					if (doesRequireHardware && deviceInfo.DevType != DeviceType.Hardware)
						continue;
					if (doesRequireReference && deviceInfo.DevType != DeviceType.Reference)
						continue;

					foreach (DeviceCombo deviceCombo in deviceInfo.DeviceComboList)
					{
						bool adapterMatchesBackBuffer = (deviceCombo.BackBufferFormat == deviceCombo.AdapterFormat);
						if (!deviceCombo.IsWindowed)
							continue;
						if (deviceCombo.AdapterFormat != primaryDesktopDisplayMode.Format)
							continue;

						// If we haven't found a compatible DeviceCombo yet, or if this set
						// is better (because it's a HAL, and/or because formats match better),
						// save it
						if (bestDeviceCombo == null || 
							bestDeviceCombo.DevType != DeviceType.Hardware && deviceInfo.DevType == DeviceType.Hardware ||
							deviceCombo.DevType == DeviceType.Hardware && adapterMatchesBackBuffer)
						{
							bestAdapterInfo = adapterInfo;
							bestDeviceInfo = deviceInfo;
							bestDeviceCombo = deviceCombo;
							if (deviceInfo.DevType == DeviceType.Hardware && adapterMatchesBackBuffer)
							{
								// This windowed m_Device combo looks great -- take it
								goto EndWindowedDeviceComboSearch;
							}
							// Otherwise keep looking for a better windowed m_Device combo
						}
					}
				}
			}

			EndWindowedDeviceComboSearch:
				if (bestDeviceCombo == null)
					return false;

			graphicsSettings.WindowedAdapterInfo = bestAdapterInfo;
			graphicsSettings.WindowedDeviceInfo = bestDeviceInfo;
			graphicsSettings.WindowedDeviceCombo = bestDeviceCombo;
			graphicsSettings.IsWindowed = true;
			graphicsSettings.WindowedDisplayMode = primaryDesktopDisplayMode;
			graphicsSettings.WindowedWidth = m_RenderTarget.ClientRectangle.Right - m_RenderTarget.ClientRectangle.Left;
			graphicsSettings.WindowedHeight = m_RenderTarget.ClientRectangle.Bottom - m_RenderTarget.ClientRectangle.Top;
			if (enumerationSettings.AppUsesDepthBuffer)
				graphicsSettings.WindowedDepthStencilBufferFormat = (DepthFormat)bestDeviceCombo.DepthStencilFormatList[0];
			graphicsSettings.WindowedMultisampleType = (MultiSampleType)bestDeviceCombo.MultiSampleTypeList[0];
			graphicsSettings.WindowedMultisampleQuality = 0;
			graphicsSettings.WindowedVertexProcessingType = (VertexProcessingType)bestDeviceCombo.VertexProcessingTypeList[0];
			graphicsSettings.WindowedPresentInterval = (PresentInterval)bestDeviceCombo.PresentIntervalList[0];

			return true;
		}


		/// <summary>
		/// Sets up graphicsSettings with best available fullscreen mode, subject to 
		/// the doesRequireHardware and doesRequireReference constraints.  
		/// </summary>
		/// <param name="doesRequireHardware">Does the device require hardware support</param>
		/// <param name="doesRequireReference">Does the device require the ref device</param>
		/// <returns>true if a mode is found, false otherwise</returns>
		public bool FindBestFullscreenMode(bool doesRequireHardware, bool doesRequireReference)
		{
			// For fullscreen, default to first HAL DeviceCombo that supports the current desktop 
			// display mode, or any display mode if HAL is not compatible with the desktop mode, or 
			// non-HAL if no HAL is available
			DisplayMode adapterDesktopDisplayMode = new DisplayMode();
			DisplayMode bestAdapterDesktopDisplayMode = new DisplayMode();
			DisplayMode bestDisplayMode = new DisplayMode();
			bestAdapterDesktopDisplayMode.Width = 0;
			bestAdapterDesktopDisplayMode.Height = 0;
			bestAdapterDesktopDisplayMode.Format = 0;
			bestAdapterDesktopDisplayMode.RefreshRate = 0;

			GraphicsAdapterInfo bestAdapterInfo = null;
			GraphicsDeviceInfo bestDeviceInfo = null;
			DeviceCombo bestDeviceCombo = null;

			foreach (GraphicsAdapterInfo adapterInfo in enumerationSettings.AdapterInfoList)
			{
				adapterDesktopDisplayMode = Manager.Adapters[adapterInfo.AdapterOrdinal].CurrentDisplayMode;
				foreach (GraphicsDeviceInfo deviceInfo in adapterInfo.DeviceInfoList)
				{
					if (doesRequireHardware && deviceInfo.DevType != DeviceType.Hardware)
						continue;
					if (doesRequireReference && deviceInfo.DevType != DeviceType.Reference)
						continue;

					foreach (DeviceCombo deviceCombo in deviceInfo.DeviceComboList)
					{
						bool adapterMatchesBackBuffer = (deviceCombo.BackBufferFormat == deviceCombo.AdapterFormat);
						bool adapterMatchesDesktop = (deviceCombo.AdapterFormat == adapterDesktopDisplayMode.Format);
						if (deviceCombo.IsWindowed)
							continue;

						// If we haven't found a compatible set yet, or if this set
						// is better (because it's a HAL, and/or because formats match better),
						// save it
						if (bestDeviceCombo == null ||
							bestDeviceCombo.DevType != DeviceType.Hardware && deviceInfo.DevType == DeviceType.Hardware ||
							bestDeviceCombo.DevType == DeviceType.Hardware && bestDeviceCombo.AdapterFormat != adapterDesktopDisplayMode.Format && adapterMatchesDesktop ||
							bestDeviceCombo.DevType == DeviceType.Hardware && adapterMatchesDesktop && adapterMatchesBackBuffer)
						{
							bestAdapterDesktopDisplayMode = adapterDesktopDisplayMode;
							bestAdapterInfo = adapterInfo;
							bestDeviceInfo = deviceInfo;
							bestDeviceCombo = deviceCombo;
							if (deviceInfo.DevType == DeviceType.Hardware && adapterMatchesDesktop && adapterMatchesBackBuffer)
							{
								// This fullscreen device combo looks great -- take it
								goto EndFullscreenDeviceComboSearch;
							}
							// Otherwise keep looking for a better fullscreen device combo
						}
					}
				}
			}

			EndFullscreenDeviceComboSearch:
				if (bestDeviceCombo == null)
					return false;

			// Need to find a display mode on the best adapter that uses pBestDeviceCombo->AdapterFormat
			// and is as close to bestAdapterDesktopDisplayMode's res as possible
			bestDisplayMode.Width = 0;
			bestDisplayMode.Height = 0;
			bestDisplayMode.Format = 0;
			bestDisplayMode.RefreshRate = 0;
			foreach (DisplayMode displayMode in bestAdapterInfo.DisplayModeList)
			{
				if (displayMode.Format != bestDeviceCombo.AdapterFormat)
					continue;
				if (displayMode.Width == bestAdapterDesktopDisplayMode.Width &&
					displayMode.Height == bestAdapterDesktopDisplayMode.Height && 
					displayMode.RefreshRate == bestAdapterDesktopDisplayMode.RefreshRate)
				{
					// found a perfect match, so stop
					bestDisplayMode = displayMode;
					break;
				}
				else if (displayMode.Width == bestAdapterDesktopDisplayMode.Width &&
					displayMode.Height == bestAdapterDesktopDisplayMode.Height && 
					displayMode.RefreshRate > bestDisplayMode.RefreshRate)
				{
					// refresh rate doesn't match, but width/height match, so keep this
					// and keep looking
					bestDisplayMode = displayMode;
				}
				else if (bestDisplayMode.Width == bestAdapterDesktopDisplayMode.Width)
				{
					// width matches, so keep this and keep looking
					bestDisplayMode = displayMode;
				}
				else if (bestDisplayMode.Width == 0)
				{
					// we don't have anything better yet, so keep this and keep looking
					bestDisplayMode = displayMode;
				}
			}

			graphicsSettings.FullscreenAdapterInfo = bestAdapterInfo;
			graphicsSettings.FullscreenDeviceInfo = bestDeviceInfo;
			graphicsSettings.FullscreenDeviceCombo = bestDeviceCombo;
			graphicsSettings.IsWindowed = false;
			graphicsSettings.FullscreenDisplayMode = bestDisplayMode;
			if (enumerationSettings.AppUsesDepthBuffer)
				graphicsSettings.FullscreenDepthStencilBufferFormat = (DepthFormat)bestDeviceCombo.DepthStencilFormatList[0];
			graphicsSettings.FullscreenMultisampleType = (MultiSampleType)bestDeviceCombo.MultiSampleTypeList[0];
			graphicsSettings.FullscreenMultisampleQuality = 0;
			graphicsSettings.FullscreenVertexProcessingType = (VertexProcessingType)bestDeviceCombo.VertexProcessingTypeList[0];
			graphicsSettings.FullscreenPresentInterval = PresentInterval.Default;

			return true;
		}


 

		/// <summary>
		/// Initialize the graphics environment
		/// </summary>
		public virtual void InitializeEnvironment()
		{
			GraphicsAdapterInfo adapterInfo = graphicsSettings.AdapterInfo;
			GraphicsDeviceInfo deviceInfo = graphicsSettings.DeviceInfo;

			windowed = graphicsSettings.IsWindowed;

			// Set up the presentation parameters
			BuildPresentParamsFromSettings();

			if (deviceInfo.Caps.PrimitiveMiscCaps.IsNullReference)
			{
				// Warn user about null ref m_Device that can't render anything
				HandleDeviceException(new NullReferenceDeviceException(), ApplicationMessage.None);
			}

			CreateFlags createFlags = new CreateFlags();
			if (graphicsSettings.VertexProcessingType == VertexProcessingType.Software)
				createFlags = CreateFlags.SoftwareVertexProcessing;
			else if (graphicsSettings.VertexProcessingType == VertexProcessingType.Mixed)
				createFlags = CreateFlags.MixedVertexProcessing;
			else if (graphicsSettings.VertexProcessingType == VertexProcessingType.Hardware)
				createFlags = CreateFlags.HardwareVertexProcessing;
			else if (graphicsSettings.VertexProcessingType == VertexProcessingType.PureHardware)
			{
				createFlags = CreateFlags.HardwareVertexProcessing | CreateFlags.PureDevice;
			}
			else
				throw new ApplicationException();

			// Make sure to allow multithreaded apps if we need them
			if (isMultiThreaded)
				createFlags |= CreateFlags.MultiThreaded;

			/*
			if(System.Windows.Forms.MessageBox.Show(this.m_RenderTarget, "Please visit http://www.shuklin.com", "Preview version", System.Windows.Forms.MessageBoxButtons.OKCancel)==System.Windows.Forms.DialogResult.OK)
			{
				try
				{
					//System.Diagnostics.Process.Start("http://www.shuklin.com/go/en/dxforms.aspx").WaitForInputIdle();
					System.Windows.Forms.Help.ShowHelp(this.m_RenderTarget, "http://www.shuklin.com/go/en/dxforms.aspx");
				}
				catch
				{
				}
			}
			*/

			try
			{

				// Create the m_Device
				m_Device = new Microsoft.DirectX.Direct3D.Device(graphicsSettings.AdapterOrdinal, graphicsSettings.DevType, 
					m_RenderTarget , createFlags, presentParams);

				// Cache our local objects
				//renderState = m_Device.RenderState;
				//sampleState = m_Device.SamplerState;
				//textureStates = m_Device.TextureState;
				
				// When moving from fullscreen to windowed mode, it is important to
				// adjust the window size after recreating the m_Device rather than
				// beforehand to ensure that you get the window size you want.  For
				// example, when switching from 640x480 fullscreen to windowed with
				// a 1000x600 window on a 1024x768 desktop, it is impossible to set
				// the window size to 1000x600 until after the display mode has
				// changed to 1024x768, because windows cannot be larger than the
				// desktop.
				if (windowed)
				{
					// Make sure main window isn't topmost, so error message is visible
					System.Drawing.Size currentClientSize = m_RenderTarget.ClientSize;
					m_RenderTarget.Size = m_RenderTarget.ClientSize;
					m_RenderTarget.SendToBack();
					m_RenderTarget.BringToFront();
					m_RenderTarget.ClientSize = currentClientSize;
				}

				// Store m_Device Caps
				graphicsCaps = m_Device.DeviceCaps;
				behavior = createFlags;

				// Store m_Device description
				if (deviceInfo.DevType == DeviceType.Reference)
					deviceStats = "REF";
				else if (deviceInfo.DevType == DeviceType.Hardware)
					deviceStats = "HAL";
				else if (deviceInfo.DevType == DeviceType.Software)
					deviceStats = "SW";

				BehaviorFlags behaviorFlags = new BehaviorFlags(createFlags);
				if ((behaviorFlags.HardwareVertexProcessing) && 
					(behaviorFlags.PureDevice))
				{
					if (deviceInfo.DevType == DeviceType.Hardware)
						deviceStats += " (pure hw vp)";
					else
						deviceStats += " (simulated pure hw vp)";
				}
				else if (behaviorFlags.HardwareVertexProcessing)
				{
					if (deviceInfo.DevType == DeviceType.Hardware)
						deviceStats  += " (hw vp)";
					else
						deviceStats += " (simulated hw vp)";
				}
				else if (behaviorFlags.MixedVertexProcessing)
				{
					if (deviceInfo.DevType == DeviceType.Hardware)
						deviceStats += " (mixed vp)";
					else
						deviceStats += " (simulated mixed vp)";
				}
				else if (behaviorFlags.SoftwareVertexProcessing)
				{
					deviceStats += " (sw vp)";
				}

				if (deviceInfo.DevType == DeviceType.Hardware)
				{
					deviceStats += ": ";
					deviceStats += adapterInfo.AdapterDetails.Description;
				}

				// Set up the fullscreen cursor
				if (showCursorWhenFullscreen && !windowed)
				{
					System.Windows.Forms.Cursor ourCursor = m_RenderTarget.Cursor;
					m_Device.SetCursor(ourCursor, true);
					m_Device.ShowCursor(true);
				}

				/*
				// Confine cursor to fullscreen window
				if (clipCursorWhenFullscreen)
				{
					if (!windowed)
					{
						System.Drawing.Rectangle rcWindow = m_RenderTarget.ClientRectangle;
					}
				}
				*/

				// Setup the event handlers for our m_Device
				m_Device.DeviceLost += new System.EventHandler(this.InvalidateDeviceObjects);
				m_Device.DeviceReset += new System.EventHandler(this.RestoreDeviceObjects);
				m_Device.Disposing += new System.EventHandler(this.DeleteDeviceObjects);
				m_Device.DeviceResizing += new System.ComponentModel.CancelEventHandler(this.EnvironmentResized);

				// Initialize the app's m_Device-dependent objects
				try
				{
					InitializeDeviceObjects(m_Device, System.EventArgs.Empty);
					RestoreDeviceObjects(m_Device, System.EventArgs.Empty);
					active = true;
					return;
				}
				catch(System.Exception ex)
				{
					HandleDeviceException(ex, ApplicationMessage.WarnSwitchToRef);
					// Cleanup before we try again
					InvalidateDeviceObjects(null, null);
					DeleteDeviceObjects(null, null);
					m_Device.Dispose();
					m_Device = null;
					if (m_RenderTarget.Disposing)
						return;
				}
			}
			catch(System.Exception ex)
			{
				// If that failed, fall back to the reference rasterizer
				if (deviceInfo.DevType == DeviceType.Hardware)
				{
					if (FindBestWindowedMode(false, true))
					{
						windowed = true;

						// Make sure main window isn't topmost, so error message is visible
						System.Drawing.Size currentClientSize = m_RenderTarget.ClientSize;
						m_RenderTarget.Size = m_RenderTarget.ClientSize;
						m_RenderTarget.SendToBack();
						m_RenderTarget.BringToFront();
						m_RenderTarget.ClientSize = currentClientSize;

						// Let the user know we are switching from HAL to the reference rasterizer
						HandleDeviceException(ex, ApplicationMessage.WarnSwitchToRef);

						InitializeEnvironment();
					}
				}
			}
		}

		public void ReleaseEnvironment()
		{
			ready = false;
			active = false;

			InvalidateDeviceObjects(null, null);
			DeleteDeviceObjects(null, null);
			if(m_Device != null)
			{
				m_Device.Dispose();
				m_Device = null;
			}
		}


		/// <summary>
		/// Build presentation parameters from the current settings
		/// </summary>
		public void BuildPresentParamsFromSettings()
		{
			presentParams.Windowed = graphicsSettings.IsWindowed;
			presentParams.BackBufferCount = 1;
			presentParams.MultiSample = graphicsSettings.MultisampleType;
			presentParams.MultiSampleQuality = graphicsSettings.MultisampleQuality;
			presentParams.SwapEffect = SwapEffect.Discard;
			presentParams.EnableAutoDepthStencil = enumerationSettings.AppUsesDepthBuffer;
			presentParams.AutoDepthStencilFormat = graphicsSettings.DepthStencilBufferFormat;
			presentParams.PresentFlag = PresentFlag.None;

			if (windowed)
			{
				presentParams.BackBufferWidth  = m_RenderTarget.ClientRectangle.Right - m_RenderTarget.ClientRectangle.Left;
				presentParams.BackBufferHeight = m_RenderTarget.ClientRectangle.Bottom - m_RenderTarget.ClientRectangle.Top;
				presentParams.BackBufferFormat = graphicsSettings.DeviceCombo.BackBufferFormat;
				presentParams.FullScreenRefreshRateInHz = 0;
				presentParams.PresentationInterval = PresentInterval.Immediate;
				presentParams.DeviceWindow = m_RenderTarget;
			}
			else
			{
				presentParams.BackBufferWidth  = graphicsSettings.DisplayMode.Width;
				presentParams.BackBufferHeight = graphicsSettings.DisplayMode.Height;
				presentParams.BackBufferFormat = graphicsSettings.DeviceCombo.BackBufferFormat;
				presentParams.FullScreenRefreshRateInHz = graphicsSettings.DisplayMode.RefreshRate;
				presentParams.PresentationInterval = graphicsSettings.PresentInterval;
				presentParams.DeviceWindow = m_RenderTarget;
			}
		}



		/// <summary>
		/// Fired when our environment was resized
		/// </summary>
		/// <param name="sender">the m_Device that's resizing our environment</param>
		/// <param name="e">Set the cancel member to true to turn off automatic m_Device reset</param>
		public void EnvironmentResized(object sender, System.ComponentModel.CancelEventArgs e)
		{
			// Check to see if we're closing or changing the form style
			if ((m_Destroying) || (isChangingFormStyle))
			{
				// We are, cancel our reset, and exit
				e.Cancel = true;
				return;
			}

			// Check to see if we're minimizing and our rendering object
			// is not the form, if so, cancel the resize
			if (/*(m_RenderTarget != this) && */(m_RenderTarget.FindForm().WindowState == System.Windows.Forms.FormWindowState.Minimized))
				e.Cancel = true;

			if (!isWindowActive) 
				e.Cancel = true;

			// Set up the fullscreen cursor
			if (showCursorWhenFullscreen && !windowed)
			{
				System.Windows.Forms.Cursor ourCursor = m_RenderTarget.Cursor;
				m_Device.SetCursor(ourCursor, true);
				m_Device.ShowCursor(true);
			}

			// If the app is paused, trigger the rendering of the current frame
			/*if (false == frameMoving)
			{
				singleStep = true;
				DXUtil.Timer(DirectXTimer.Start);
				DXUtil.Timer(DirectXTimer.Stop);
			}*/
		}

		


		/// <summary>
		/// Called when user toggles between fullscreen mode and windowed mode
		/// </summary>
		public void ToggleFullscreen()
		{
			int AdapterOrdinalOld = graphicsSettings.AdapterOrdinal;
			DeviceType DevTypeOld = graphicsSettings.DevType;

			isHandlingSizeChanges = false;
			ready = false;

			// Toggle the windowed state
			windowed = !windowed;

			System.Windows.Forms.Form form = m_RenderTarget.FindForm();

			// Save our maximized settings..
			if (!windowed && isMaximized)
			{
				form.WindowState = System.Windows.Forms.FormWindowState.Normal;
			}

			graphicsSettings.IsWindowed = windowed;

			// If AdapterOrdinal and DevType are the same, we can just do a Reset().
			// If they've changed, we need to do a complete device teardown/rebuild.
			if (false && graphicsSettings.AdapterOrdinal == AdapterOrdinalOld &&
				graphicsSettings.DevType == DevTypeOld)
			{
				// Resize the 3D device
				try
				{
					BuildPresentParamsFromSettings();
					m_Device.Reset(presentParams);
					EnvironmentResized(m_Device, new System.ComponentModel.CancelEventArgs());
				}
				catch 
				{
					//if (windowed)
					ForceWindowed();
					//else
					//	throw new Exception();
				}
			}
			else
			{
				ReleaseEnvironment();
				InitializeEnvironment();
			}

			// When moving from fullscreen to windowed mode, it is important to
			// adjust the window size after resetting the device rather than
			// beforehand to ensure that you get the window size you want.  For
			// example, when switching from 640x480 fullscreen to windowed with
			// a 1000x600 window on a 1024x768 desktop, it is impossible to set
			// the window size to 1000x600 until after the display mode has
			// changed to 1024x768, because windows cannot be larger than the
			// desktop.

			if (windowed)
			{
				form = m_RenderTarget.FindForm();

				isChangingFormStyle = true;
				// if our render target is the main window and we haven't said 
				// ignore the menus, add our menu
				//if ((ourRenderTarget == this) && (isUsingMenus))
				//	this.m_RenderTarget.Menu = mnuMain;
				form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
				isChangingFormStyle = false;

				this.m_RenderTarget.SendToBack();
				this.m_RenderTarget.BringToFront();
				this.m_RenderTarget.ClientSize = storedSize;
				this.m_RenderTarget.Location = storedLocation;

				// We were maximized, restore that state
				if (isMaximized)
				{
					form.WindowState = System.Windows.Forms.FormWindowState.Maximized;
				}
			}
			else
			{
				form = m_RenderTarget.FindForm();

				isChangingFormStyle = true;
				//if (form.Menu != null)
				//	form.Menu = null;

				form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
				form.Size  = new System.Drawing.Size(graphicsSettings.DisplayMode.Width, graphicsSettings.DisplayMode.Height);

				isChangingFormStyle = false;
			}
			isHandlingSizeChanges = true;
			ready = true;
		}




		/// <summary>
		/// Switch to a windowed mode, even if that means picking a new device and/or adapter
		/// </summary>
		public void ForceWindowed()
		{
			if (ready && windowed)
				return;

			if (!FindBestWindowedMode(false, false))
			{
				return;
			}
			windowed = true;

			// Now destroy the current 3D device objects, then reinitialize

			ready = false;

			if(m_Device!=null)
			{
				// Release display objects, so a new device can be created
				m_Device.Dispose();
				m_Device = null;
			}

			// Create the new device
			try
			{
				InitializeEnvironment();
			}
			catch (System.Exception e)
			{
				HandleDeviceException(e,ApplicationMessage.ApplicationMustExit);
			}
			/*catch
			{
				HandleDeviceException(new System.Exception(),ApplicationMessage.ApplicationMustExit);
			}*/
			ready = true;
		}

		/// <summary>
		/// Called when our sample has nothing else to do, and it's time to render
		/// </summary>
		public void FullRender()
		{
			// Render a frame during idle time (no messages are waiting)
			if (active && ready)
			{
				try 
				{
					if ((deviceLost) /*|| (m_DomainContext==null || m_DomainContext.PrimaryWindow== null || m_DomainContext.PrimaryWindow.ActiveComponent != this)*/)
					{
						// Yield some CPU time to other processes
						System.Threading.Thread.Sleep(100); // 100 milliseconds
					}
					// Render a frame during idle time
					if (active)
					{
						Render3DEnvironment();
					}
				}
				catch (Exception ee)
				{
					System.Windows.Forms.MessageBox.Show("An exception has occurred.  This sample must exit.\r\n\r\n" + ee.ToString(), "Exception", 
						System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
					m_RenderTarget.Dispose();
				}
			}
		}

		/// <summary>
		/// Draws the scene 
		/// </summary>
		public void Render3DEnvironment()
		{
			if(m_Device.PresentationParameters.DeviceWindowHandle != this.m_RenderTarget.Handle)
			{ 
				m_Device.PresentationParameters.DeviceWindowHandle = this.m_RenderTarget.Handle; 
				m_Device.Reset(m_Device.PresentationParameters);
			}

			if (deviceLost)
			{
				try
				{
					// Test the cooperative level to see if it's okay to render
					m_Device.TestCooperativeLevel();
				}
				catch (DeviceLostException)
				{
					// If the m_Device was lost, do not render until we get it back
					//isHandlingSizeChanges = false;
					isWindowActive = false;
					return;
				}
				catch (DeviceNotResetException)
				{
					// Check if the m_Device needs to be resized.

					// If we are windowed, read the desktop mode and use the same format for
					// the back buffer
					if (windowed)
					{
						GraphicsAdapterInfo adapterInfo = graphicsSettings.AdapterInfo;
						graphicsSettings.WindowedDisplayMode = Manager.Adapters[adapterInfo.AdapterOrdinal].CurrentDisplayMode;
						presentParams.BackBufferFormat = graphicsSettings.WindowedDisplayMode.Format;
					}

					// Reset the m_Device and resize it
					m_Device.Reset(m_Device.PresentationParameters);
					EnvironmentResized(m_Device, new System.ComponentModel.CancelEventArgs());
				}
				deviceLost = false;
			}

			// Get the app's time, in seconds. Skip rendering if no time elapsed
			/*float fAppTime        = DXUtil.Timer(DirectXTimer.GetApplicationTime);
			float fElapsedAppTime = DXUtil.Timer(DirectXTimer.GetElapsedTime);
			if ((0.0f == fElapsedAppTime) && frameMoving)
				return;*/

			/*#warning "m_Device.Viewport = viewport"
			Viewport viewport = m_Device.Viewport;
			viewport.X = 0;
			viewport.Y = 0;
			viewport.Width = m_RenderTarget.ClientSize.Width;
			viewport.Height = m_RenderTarget.ClientSize.Height;
			m_Device.Viewport = viewport;*/

			// FrameMove (animate) the scene
			if (frameMoving || singleStep)
			{
				// Store the time for the app
				//appTime        = fAppTime;
				//elapsedTime = fElapsedAppTime;

				// Frame move the scene
				this.OnUpdateScene(new DeviceEventArgs(this.m_Device));

				singleStep = false;
			}


			// Render the scene as normal
			this.OnRenderScene(new RenderEventArgs(this.m_Device, this.SurfaceRectangle));

			//UpdateStats();

			try
			{
				// Show the frame on the primary surface.
				m_Device.Present();
			}
			catch(DeviceLostException)
			{
				deviceLost = true;
			}
		}



		/// <summary>
		/// Called in to toggle the pause state of the app.
		/// </summary>
		/// <param name="pause">true if the simulation should pause</param>
		public void Pause(bool pause)
		{
			appPausedCount  += (int)(pause ? +1 : -1);
			ready = ((appPausedCount > 0) ? false : true);
			/*
						// Handle the first pause request (of many, nestable pause requests)
						if (pause && (1 == appPausedCount))
						{
							// Stop the scene from animating
							if (frameMoving)
								DXUtil.Timer(DirectXTimer.Stop);
						}

						if (0 == appPausedCount)
						{
							// Restart the timers
							if (frameMoving)
								DXUtil.Timer(DirectXTimer.Start);
						}*/
		}

		public override void Invalidate()
		{
			//base.Invalidate ();
			if(m_RenderTarget!=null)
			{
				Cerebrum.Direct3D.Forms.Control ctl = null;
			
				if(m_MouseReceiver != null)
				{
					ctl = m_MouseReceiver;
				}
				else
				{
					System.Drawing.Point pnt = m_RenderTarget.PointToClient(System.Windows.Forms.Cursor.Position);
					ctl = this.GetChildAtPoint(new PointF(pnt.X, pnt.Y), false);
					if(ctl==null) ctl = this;
				}

				ctl.ForceCursor(m_RenderTarget);

				m_RenderTarget.Invalidate();
			}
		}


		protected Cerebrum.Direct3D.Forms.Control m_MouseReceiver = null;
		protected Cerebrum.Direct3D.Forms.Control m_MouseHovered = null;

		private void RenderTarget_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
			try
			{
				if(m_Device!=null)
					Render3DEnvironment();
			}
			catch(System.Exception ex)
			{
				HandleDeviceException(ex, ApplicationMessage.ApplicationMustExit);
			}
		}

		private void RenderTarget_Resize(object sender, System.EventArgs e)
		{
			System.Windows.Forms.Form form = m_RenderTarget==null?null:m_RenderTarget.FindForm();
			if(form==null) return;
			
			if (ready && windowed && isHandlingSizeChanges)
			{
				// Are we maximized?
				isMaximized = (form.WindowState == System.Windows.Forms.FormWindowState.Maximized);
				if (!isMaximized)
				{
					storedSize = form.ClientSize;
					storedLocation = form.Location;
				}
			}
			active = !(form.WindowState == System.Windows.Forms.FormWindowState.Minimized || m_RenderTarget.Visible == false);

			if(form.WindowState == System.Windows.Forms.FormWindowState.Minimized) isWindowActive = false;

			if(form.Visible && form.WindowState != System.Windows.Forms.FormWindowState.Minimized && m_RenderTarget.Visible)
			{
				this.SetBounds(0, 0, m_RenderTarget.ClientSize.Width, m_RenderTarget.ClientSize.Height, BoundsSpecified.All);
				this.Invalidate();
			}
		}

		private void RenderTarget_Move(object sender, EventArgs e)
		{
			System.Windows.Forms.Form form = m_RenderTarget==null?null:m_RenderTarget.FindForm();
			if(form==null) return;
			
			if(ready && windowed && isHandlingSizeChanges && form.WindowState == System.Windows.Forms.FormWindowState.Normal)
			{
				storedLocation = form.Location;
			}
		}

		protected PointF m_MouseDownLocation;
		protected System.Windows.Forms.MouseButtons m_MouseDownButton;

		private void RenderTarget_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			m_MouseDownLocation = new PointF(e.X, e.Y);
			m_MouseDownButton = e.Button;

			Cerebrum.Direct3D.Forms.Control ctl = this.GetChildAtPoint(m_MouseDownLocation, false);
			if(ctl==null) ctl = this;
				
			RectangleF _rect = ctl.SurfaceRectangle;
			ctl.OnMouseDown(new System.Windows.Forms.MouseEventArgs(e.Button, e.Clicks, (int)(e.X - _rect.X), (int)(e.Y - _rect.Y), e.Delta));

			m_MouseReceiver = ctl;
		}

		private void RenderTarget_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			Cerebrum.Direct3D.Forms.Control ctl = null;
			
			if(m_MouseReceiver != null)
			{
				ctl = m_MouseReceiver;
			}
			else
			{
				ctl = this.GetChildAtPoint(new PointF(e.X, e.Y), false);
				if(ctl==null) ctl = this;
			}

			if(m_MouseHovered!=ctl && m_MouseHovered!=null)
			{
				m_MouseHovered.OnMouseLeave(System.EventArgs.Empty);
				m_MouseHovered = null;
			}

			RectangleF _rect = ctl.SurfaceRectangle;
			System.Windows.Forms.MouseEventArgs me = new System.Windows.Forms.MouseEventArgs(e.Button, e.Clicks, (int)(e.X - _rect.X), (int)(e.Y - _rect.Y), e.Delta);
			
			bool needHover = false;
			if(m_MouseHovered == null)
			{
				m_MouseHovered = ctl;
				ctl.OnMouseEnter(me);
				needHover = true;
			}

			ctl.OnMouseMove(me);

			if(needHover)
			{
				ctl.OnMouseHover(me);
			}
		}

		private void RenderTarget_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			Cerebrum.Direct3D.Forms.Control ctl = null;
			
			if(m_MouseReceiver != null)
			{
				ctl = m_MouseReceiver;
			}
			else
			{
				ctl = this.GetChildAtPoint(new PointF(e.X, e.Y), false);
				if(ctl==null) ctl = this;
			}	
				
			RectangleF _rect = ctl.SurfaceRectangle;
			ctl.OnMouseUp(new System.Windows.Forms.MouseEventArgs(e.Button, e.Clicks, (int)(e.X - _rect.X), (int)(e.Y - _rect.Y), e.Delta));

			m_MouseReceiver = null;
		}

		private void RenderTarget_MouseWheel(object sender, MouseEventArgs e)
		{
			Cerebrum.Direct3D.Forms.Control ctl = null;
			
			if(m_MouseReceiver != null)
			{
				ctl = m_MouseReceiver;
			}
			else
			{
				ctl = this.GetChildAtPoint(new PointF(e.X, e.Y), false);
				if(ctl==null) ctl = this;
			}	
				
			RectangleF _rect = ctl.SurfaceRectangle;
			ctl.OnMouseWheel(new System.Windows.Forms.MouseEventArgs(e.Button, e.Clicks, (int)(e.X - _rect.X), (int)(e.Y - _rect.Y), e.Delta));

			m_MouseReceiver = null;
		}

		private void RenderTarget_Click(object sender, EventArgs e)
		{
			Cerebrum.Direct3D.Forms.Control ctl = this.GetChildAtPoint(m_MouseDownLocation, false);
			if(ctl==null) ctl = this;

			if(ctl.Enabled)
			{
				RectangleF _rect = ctl.SurfaceRectangle;
				ctl.OnClick(new System.Windows.Forms.MouseEventArgs(m_MouseDownButton, 1, (int)(m_MouseDownLocation.X - _rect.X), (int)(m_MouseDownLocation.Y - _rect.Y), 0));
			}
		}

		private void RenderTarget_DoubleClick(object sender, EventArgs e)
		{
			Cerebrum.Direct3D.Forms.Control ctl = this.GetChildAtPoint(m_MouseDownLocation, false);
			if(ctl==null) ctl = this;

			if(ctl.Enabled)
			{
				RectangleF _rect = ctl.SurfaceRectangle;
				ctl.OnDoubleClick(new System.Windows.Forms.MouseEventArgs(m_MouseDownButton, 1, (int)(m_MouseDownLocation.X - _rect.X), (int)(m_MouseDownLocation.Y - _rect.Y), 0));
			}
		}

		private void RenderTarget_HandleCreated(object sender, EventArgs e)
		{
			if(ready)
				this.CreateGraphicsDevice();
		}

		private void RenderTarget_HandleDestroyed(object sender, EventArgs e)
		{
			this.ReleaseEnvironment();
		}

		private void RenderTarget_MouseEnter(object sender, EventArgs e)
		{

		}

		private void RenderTarget_MouseLeave(object sender, EventArgs e)
		{
			if(m_MouseHovered!=null)
			{
				m_MouseHovered.OnMouseLeave(System.EventArgs.Empty);
				m_MouseHovered = null;
			}
		}

		private void RenderTarget_VisibleChanged(object sender, EventArgs e)
		{
			bool _oldVisible = this.Visible;
			m_ParentVisible = m_RenderTarget.Visible;
			bool _newVisible = this.Visible;
			if(_oldVisible != _newVisible)
				this.OnVisibleChanged(System.EventArgs.Empty);
		}

		private void RenderTarget_GotFocus(object sender, EventArgs e)
		{
			//isHandlingSizeChanges = true;
			isWindowActive = true;
			this.OnGotFocus(e);
		}

		private void RenderTarget_Disposed(object sender, EventArgs e)
		{
			ready = false;
			m_RenderTarget = null;
			m_Device = null;
		}
	}





	#region Enums for D3D Applications
	/// <summary>
	/// Messages that can be used when displaying an error
	/// </summary>
	public enum ApplicationMessage 
	{ 
		None, 
		ApplicationMustExit, 
		WarnSwitchToRef
	};
	#endregion


	

	/// <summary>
	/// An exception for when the ReferenceDevice is null
	/// </summary>
	public class NullReferenceDeviceException : System.ApplicationException
	{
		/// <summary>
		/// Return information about the exception
		/// </summary>
		public override string Message
		{
			get
			{
				string strMsg = string.Empty;
				strMsg = "Warning: Nothing will be rendered.\n";
				strMsg += "The reference rendering m_Device was selected, but your\n";
				strMsg += "computer only has a reduced-functionality reference m_Device\n";
				strMsg += "installed.  Install the DirectX SDK to get the full\n";
				strMsg += "reference m_Device.\n";

				return strMsg;
			}
		}
	}

	/// <summary>
	/// Exception informing user no compatible devices were found
	/// </summary>
	public class NoCompatibleDevicesException : System.ApplicationException 
	{
		/// <summary>
		/// Return information about the exception
		/// </summary>
		public override string Message
		{
			get
			{
				string strMsg = string.Empty;
				strMsg = "This module cannot run in a desktop\n";
				strMsg += "window with the current display settings.\n";
				strMsg += "Please change your desktop settings to a\n";
				strMsg += "16- or 32-bit display mode and re-run this\n";
				strMsg += "sample.";

				return strMsg;
			}
		}
	}
}

